#pragma once
#include <sys/epoll.h>
#include "comm.hpp"
#include "Socket.hpp"
#include "Log.hpp"

using namespace SocketModule;
using namespace LogModule;

class EPollServer
{
    const static int size = 64;
    const int static defaultfd = -1;

public:
    EPollServer(uint16_t port) : _listensocket(std::make_unique<TcpSocket>()), _isrunning(false), _epfd(defaultfd)
    {
        _listensocket->BuildTcpSocket(port);
        _epfd = epoll_create(4096);
        if (_epfd < 0)
        {
            LOG(LogLevel::FATAL) << "epoll create error";
            exit(EPOLL_CREATE_ERR);
        }
        LOG(LogLevel::INFO) << "epoll create success: " << _epfd;
        // 将listensocket设置到内核中
        struct epoll_event eve;
        eve.events = EPOLLIN;
        eve.data.fd = _listensocket->Fd();
        int n = epoll_ctl(_epfd, EPOLL_CTL_ADD, _listensocket->Fd(), &eve);
        if (n < 0)
        {
            LOG(LogLevel::FATAL) << "add listensocket error";
            exit(EPOLL_CTL_ERR);
        }
    }

    void Start()
    {
        _isrunning = true;
        int timeout = 1000;
        while (true)
        {
            int n = epoll_wait(_epfd, _reves, size, timeout);
            switch (n)
            {
            case 0:
                LOG(LogLevel::DEBUG) << "time out";
                break;
            case -1:
                LOG(LogLevel::DEBUG) << "wait error";
                break;
            default:
                Dispatcher(n);
                break;
            }
        }
    }

    // 事件派发
    void Dispatcher(int num)
    {
        LOG(LogLevel::DEBUG) << "event ready";
        for (int i = 0; i < num; i++)
        {
            int sockfd = _reves[i].data.fd;
            uint16_t event = _reves[i].events;
            if (event | EPOLLIN)
            {
                if (sockfd == _listensocket->Fd())
                    Accepter();
                else
                    Recver(sockfd);
            }
            if (event | EPOLLOUT)
            {
            }
        }
    }

    // 连接管理器
    void Accepter()
    {
        InetAddr client;
        int sockfd = _listensocket->Accept(&client);
        if (sockfd >= 0)
        {
            LOG(LogLevel::DEBUG) << "A client come: " << client.StringAddr()
                                 << " fd: " << sockfd;
            struct epoll_event eve;
            eve.events = EPOLLIN;
            eve.data.fd = sockfd;
            int n = epoll_ctl(_epfd, EPOLL_CTL_ADD, sockfd, &eve);
            if (n < 0)
            {
                LOG(LogLevel::WARNING) << "add new sockfd failed";
            }
            else
            {
                LOG(LogLevel::DEBUG) << "add new sockfd success";
            }
        }
    }

    // IO接收器
    void Recver(int fd)
    {
        char buff[1024];
        ssize_t n = recv(fd, buff, sizeof(buff) - 1, 0);
        if (n > 0)
        {
            buff[n] = 0;
            std::cout << "client say: " << buff;
        }
        else if (n == 0)
        {
            LOG(LogLevel::INFO) << "client quit";
            int m = epoll_ctl(_epfd, EPOLL_CTL_DEL, fd, nullptr);
            if(m < 0)
            {
                LOG(LogLevel::DEBUG) << "fd delete failed";
            }
            LOG(LogLevel::DEBUG) << "fd delete success";
            close(fd);
        }
        else
        {
            LOG(LogLevel::INFO) << "recv error";
            int m = epoll_ctl(_epfd, EPOLL_CTL_DEL, fd, nullptr);
            if(m < 0)
            {
                LOG(LogLevel::DEBUG) << "fd delete failed";
            }
            LOG(LogLevel::DEBUG) << "fd delete success";
            close(fd);
        }
    }

    void Stop()
    {
        _isrunning = false;
        if (_epfd >= 0)
            close(_epfd);
    }

    ~EPollServer() {}

private:
    std::unique_ptr<Socket> _listensocket;
    bool _isrunning;
    int _epfd;

    struct epoll_event _reves[size];
};